/*
 Copyright (c) 2020-2023 Xiamen Yaji Software Co., Ltd.

 https://www.cocos.com/

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
 of the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
*/

import { Node, find, game } from "cc";

import { Action } from "../../core/action/action";
import { Singleton } from "../../util/Singleton";
import { UI } from '../../core/ui/ui';
import { Bind } from '../../core/bind/bind'
// import { Local } from "../../core/localization/local";
import { Save } from "../../util/save";
import { Msg } from "../../util/msg";
import { Stack } from "../../util/data-structure";
import { Level } from "../level/level";
import { Sound } from "../../core/audio/sound";
import { Notify } from "../../util/io/notify";
import { utils } from "../../util/util";
import { PostMessageHandler } from "../../util/postMessageHandler";
import { UrlUtil } from "../../util/urlUtil";


import * as dataCore from "./data-core";
import { BindUI } from "../../core/ui/ui-base";
// import { GameSet } from "./game-set";
import { ResPool } from "../../core/res/res-pool";
declare var window: Window;

   

export class Game extends Singleton {

    // Action objects are used to execute the current set of actions.
    //动作对象用于执行当前的动作集合
    _action: Action | undefined;

    // The stack collection is used to manage the current node order.
    //栈集合用于管理当前节点的顺序
    _stack: Stack<string> = new Stack(5);

    // The key-value collection is used to store all the game node data.
    //键值集合用于存储所有游戏行为节点数据
    _nodes: { [key: string]: any } = {};

    // Game data object to store static game data.
    //游戏数据对象，用于存储静态游戏数据
    _data: { [key: string]: any } = {};

    // If or not the game is initialized, true is initialized, false is not initialized.
    //是否已经初始化游戏，true为已经初始化，false为未初始化
    _isInit = false;

    // Total game time, used to store the total time the game has been running. 
    //游戏总时间，用于存储游戏运行的总时间
    _totalGameTime = 0;

    // The next storage time point is used to control the event interval control for automatic storage. 
    //下一次存储时间点，用于控制自动存储的事件间隔控制
    _nextSaveTime = 0;

    // The root node of all pool objects game runtime.
    //游戏运行时所有对象池根节点
    _poolNode: Node | null | undefined;

    _camera: Node | null | undefined;

    // Safe time for back
    //返回安全时间
    backSafeTime = 0;

    public init (): void {
        window["game"] = this;

        this._camera = find('init')?.getChildByName('camera-node')?.getChildByName('VCam0');
        console.log(this._camera,"this._camera")

        // Find the root node of all pool objects.
        //找到对象池根节点
        this._poolNode = find('init')?.getChildByName('objects-pool');

        // Initialize the data core.
        //初始化数据核心
        dataCore.Init();

        // Initialize pool.
        //初始化对象池
        ResPool.Instance.initPool(this._poolNode);

        // Initialize local storage.
        Save.Instance.init();

        // Initialize the game data.
        //初始化游戏数据
        this._data = dataCore.DataGameInst._data;
        
        // Initialize game action data.
        //初始化游戏动作数据
        this._action = new Action(this._data.action_data);

        // Get the game node data.
        //获取游戏节点数据
        this._nodes = this._data['nodes']||{};

        //初始化UI绑定
        BindUI.init();

        //根据data内容初始化绑定器
        Bind.Instance.initData(this._data['events']);

        //ui管理对象初始化，这里需要定义data—game里的ui_order
        //用于控制ui的显示顺序，并且UI初始化时会预加载配置的ui面板
        UI.Instance.init();

        // Initialize the sound manager.
        //初始化声音管理器
        Sound.init();

        //通过url获取参数
        var level = UrlUtil.Instance.getQueryString("level");
        Level.Instance._levelIndex = Number(level);

        //初始化关卡
        Level.Instance.init();

     
        // Register game node stack operation method.
        Msg.on('push', (key: string) => { Game.Instance.push(key); });
        Msg.on('root', (key: string) => { Game.Instance.root(key); });
        Msg.on('next', this.next.bind(this));
        Msg.on('back', this.back.bind(this));
        Msg.on('camera-watch',  (_node: Node) => { Game.Instance.cameraWatch(_node); });
        Msg.on('camera-ani-hit',  () => { Game.Instance.cameraAniHit(); });

        // Push the game initial node into the stack data.
        //将游戏初始行为节点推入栈数据

        this.push(this._data['start_action_node']);

        //Set game initialization to true.
        this._isInit = true;

        // Check if a message currently exists. 
        // Why it is detected after initialization: because messages may not be displayed properly during initialization.
        //检测是否存在消息，为什么在初始化后检测：因为初始化期间消息可能无法正常显示
        Notify.Instance.check_notify();

        this.tryRegisterPostMessage();
    }

    /**
     * Jump to the next game node. 
     */
    //跳转到下一个游戏节点  
    public next (): void {
        var cur = this._stack.cur();
        const nextAction = this._nodes[cur]?.next;
        if (nextAction) this.push(nextAction);
    }

    /**
     * Return to the previous game node.
     */
    //返回到上一个游戏节点
    public back (): void {
        if (game.totalTime - this.backSafeTime < 50) return;
        this.backSafeTime = game.totalTime;
        const preNode = this._stack.pop();
        this._action!.off(preNode);
    }

    /**
     * Returns to the game root node corresponding to the name.
     * @param name 
     */
    //返回到对应名字的游戏根节点
    public root (name: string): void {
        var size = this._stack.size() - 1;
        for (let i = 0; i < size - 1; i++) {
            let pre = this._stack.pop();
            this._action!.off(pre);
        }
    }

    /**
     * Pushes a new game node.
     * @param name node name.
     */
    //推入一个新的游戏行为节点
    public push (name: string) {
        dataCore.DataGameInst._currentGameNodeName = name;
        //避免多个节点同时执行end动作，导致动作混乱
        //is_pop为false时，弹出
        if(!this._nodes[name]){
            this._nodes[name]={};
        }
        if (!this._nodes[name].is_pop && this._stack.size() > 0) {
            var pre = this._stack.pop();
            this._action!.off(pre);
        }
        this._stack.push(name);
        this._action!.on(name);
    }

    //相机观察某个节点
    public cameraWatch (watch_node: Node) {
        console.log(watch_node,"watch_node")
        this._camera.active = true;
        // watch_node.addChild(this._camera);
        var camera_obj = this._camera.getComponent("VirtualCamera");
        console.log(camera_obj,"camera_obj")
        window["acac"] = camera_obj
        //这里跟踪会有问题，暂时先用follow，如果打开follow会出现视角向下移动的问题
        // camera_obj["lookAt"] = watch_node;
        camera_obj["follow"] = watch_node;
    }

    //相机碰撞晃动
    public cameraAniHit () {
        var camera_obj = this._camera.getComponent("VirtualCamera");
        camera_obj["noise"].amplitudeGain+=0.3;
        camera_obj["noise"].frequencyGain+=20;
        utils.delay(()=>{
            camera_obj["noise"].amplitudeGain-=0.3;
            camera_obj["noise"].frequencyGain-=20;
        },0.1
        )
    }

    //尝试组册网页的postMessage事件
    public tryRegisterPostMessage () {
        // PostMessageHandler.Instance.addMessageHandler(
        //     "setLevelIndex",
        //     (data: any) => {
        //         Level.Instance._levelIndex = data._levelIndex;
        //     }
        // );
        //游戏结束,发送消息
        Msg.on("postMsgToParent", (data: any) => {
            PostMessageHandler.Instance.postMessage("someDataFromChildPage", data);
            }
        );
    }
    

    //update是执行的每一帧
    public update (deltaTime: number): void {
        // If initialization false returns, initialization success continues.
        if (!this._isInit) return;

        //Increase the game time, The accumulated time is the length of each frame.
        this._totalGameTime += deltaTime;

        // Update the game action logic every frame.
        Game.Instance._action.update(deltaTime);

        // // Update the level logic every frame.
        Level.Instance.update(deltaTime);

        // // Update the binder logic every frame.
        Bind.Instance.update(deltaTime);

        // Automatic save judgment: true is on, false is off
        if (this._data.auto_save) {
            // When the current total time of the game is greater than the next time node. 
            // true is to update the game storage logic. 
            // false is to wait.
            if (this._totalGameTime > this._nextSaveTime) {
                // Updates the current game time stats.
                Save.Instance.statisticsTime('game', Math.floor(this._data.next_save_time));
                this._nextSaveTime += this._data.next_save_time
            }
        }

    }

}
